/*
 * DatabaseInfo.java
 *
 * Created on September 5, 2007, 9:11 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package dnbW.dbW;

import dnbW.uiW.dbW.DataSourceNodeObject;
import dnbW.uiW.queryW.modelW.JoinManager;
import java.io.Serializable;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Collection;
import java.util.HashMap;
import javax.swing.tree.TreeModel;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.DefaultMutableTreeNode;

/**
 * This is a container for the database information. 
 * A dababase engine is also provided. Any database related tasks
 * should be performed through the database engine API.
 * @author Colin
 */
public class DatabaseInfo implements Serializable{

    private static final long serialVersionUID = 10000L;
    
    public static final String SCHEMA_TREE_ROOT = "<root>";
    
    public static int HOST_NAME = 0;
    public static int PORT_NUMBER = 1;
    public static int DB_NAME = 2;
    public static int USER_NAME = 3;
    public static int PASSWORD = 4;

    public static String DEFAULT_DATABASE_NAME = "No Database Selected";
    public static DatabaseInfo DEFAULT_DATABASE = new DatabaseInfo("localhost", DEFAULT_DATABASE_NAME, null, null);
    
    // Database properties
    // Unmodifiable, user must provide all these parameters in the constructor
    // currently hostname and port are not used
    // <editor-fold desc="HostName">
    private String hostName = "localhost";

    public String getHostName() {
        return hostName;
    }
    // </editor-fold>

    // <editor-fold desc="Port">
    private String port = "1433";
    
    public String getPort() {
        return port;
    }
    // </editor-fold>

    // <editor-fold desc="DbName">
    private String dbName;

    public String getDbName() {
        return dbName;
    }
    // </editor-fold>

    // <editor-fold desc="UserName">
    private String userName;

    public String getUserName() {
        return userName;
    }
    // </editor-fold>

    // <editor-fold desc="Password">
    private String password;

    public String getPassword() {
        return password;
    }
    // </editor-fold>
    
    // <editor-fold desc="Database Engine">
    // database engine that provides service to this database
    private transient DatabaseEngine engine;
    
    public DatabaseEngine getEngine() {
        return engine;
    }

    public void setEngine(DatabaseEngine engine) {
        if(getEngine() == null)
            this.engine = engine;
    }
    // </editor-fold>

    // <editor-fold desc="Database connection">
    public Connection getDbConnection() {
        return this.engine.getConnection();
    }
    // </editor-fold>

    // <editor-fold desc="Data Source List">
    /**
     * A map from data source name to the data source of the database
     */
    private HashMap<String, DataSource> dataSources;

    public Collection<String> getDataSourceNames() {
        return dataSources.keySet();
    }

    public Collection<DataSource> getDataSources() {
        return dataSources.values();
    }

    public DataSource getDataSource(String dataSourceName) {
        return dataSources.get(dataSourceName);
    }
    // </editor-fold>

    // <editor-fold desc="Tree Model">
    private DefaultTreeModel treeModel;

    public TreeModel getTreeModel() {
        return treeModel;
    }
    // </editor-fold>
    
    // <editor-fold desc="Connected">
    // connection status
    private transient boolean connected = false;
    
    public boolean isConnected() {
        return connected;
    }

    public void setConnected(boolean connected) {
        this.connected = connected;
    }
    // </editor-fold>

    // <editor-fold desc="Join Manager">
    private JoinManager joinManager = new JoinManager();

    public JoinManager getJoinManager() {
        return this.joinManager;
    }
    // </editor-fold>
    
    // <editor-fold desc="Schema Available">
    // status code if schema is available
    private transient boolean schemaAvailable = false;
    
    public boolean isSchemaAvailable() {
        return schemaAvailable;
    }

    public void setSchemaAvailable(boolean schemaAvailable) {
        this.schemaAvailable = schemaAvailable;
    }
    // </editor-fold>
    
    
    public DatabaseInfo()
    {
        
    }
    
    public DatabaseInfo(
            String hostName,
            String dbName,
            String userName,
            String password) {
        this.hostName = hostName;
        this.dbName = dbName;
        this.userName = userName;
        this.password = password;
        this.dataSources = new HashMap<String, DataSource>();
        this.treeModel = createDefaultSchemaTree();
    }

    public void connect() throws Exception{
        getEngine().connect();
        this.setConnected(true);
    }
    
    @Override
    public String toString() {
        return dbName + "@" + getHostName();
    }

    public boolean isDefault() {
        return DEFAULT_DATABASE_NAME.equals(this.dbName);
    }
    
    public boolean hasDataSource(String dataSourceName) {
        return this.dataSources.containsKey(dataSourceName);
    }

    public List retrieveDataSources() {
        String datasource = null;
        List<String> dataSources = new ArrayList<String>();
        try {
            Collection<DataSource> retrievedDataSources = this.engine.retrieveDataSourceList();//SucxentDatabaseEngine.java line 120
            for (DataSource dataSource : retrievedDataSources) {
                DefaultMutableTreeNode node = this.addDataSourceNode(dataSource.getName());
                dataSource.setTreeNode(node);
                this.dataSources.put(dataSource.getName(), dataSource);
                datasource = dataSource.getName();
                dataSources.add(datasource);
            }
            
        }
        catch (Exception ex) {
            System.err.println(ex.getMessage());
            ex.printStackTrace(System.err);
        }
        return dataSources;
    }

    public void addDataSource(String dataSourceName) throws Exception {
        // Is the data source added?
        if (this.hasDataSource(dataSourceName)) {
            // Yes. Throw an exception.
            throw new Exception("Data source: " + dataSourceName + " already exists");
        }
        DataSource dataSource = this.engine.addDataSource(dataSourceName);
        DefaultMutableTreeNode node = this.addDataSourceNode(dataSourceName);
        dataSource.setTreeNode(node);
        this.dataSources.put(dataSourceName, dataSource);
    }

    private DefaultMutableTreeNode addDataSourceNode(String dataSourceName) {
        // set up the schema
        DefaultMutableTreeNode schemaRoot = (DefaultMutableTreeNode) this.treeModel.getRoot();
        DefaultMutableTreeNode firstChild = (DefaultMutableTreeNode) schemaRoot.getFirstChild();

        if (DataSourceNodeObject.getEmptyDataSourceNodeObject().equals(firstChild.getUserObject())) {
            schemaRoot.removeAllChildren();
        }

        DataSourceNodeObject dsnObj = new DataSourceNodeObject(dataSourceName);
        DefaultMutableTreeNode dsn = new DefaultMutableTreeNode(dsnObj);
        dsn.add(new DefaultMutableTreeNode(DataSource.EMPTY_DATASOURCE_INFO));
        schemaRoot.add(dsn);
        this.treeModel.reload();
        return dsn;
    }

    public void deleteDataSource(String dataSourceName) throws Exception {
        // Is the data source added?
        if (!this.hasDataSource(dataSourceName)) {
            // Yes. Throw an exception.
            throw new Exception("Data source " + dataSourceName + " does not exist");
        }
        // delete the data source in the database
        this.engine.deleteDataSource(dataSourceName);

        this.dataSources.remove(dataSourceName);

//        removedDataSource.getTreeNode().removeFromParent();
//        this.treeModel.reload();
    }

    public static DefaultTreeModel createDefaultSchemaTree() {
        // set up the default schema tree model with one root node for each database
        // and one child node to indicate no data source has been loaded.
        DefaultMutableTreeNode schemaRoot = new DefaultMutableTreeNode(SCHEMA_TREE_ROOT);
        DataSourceNodeObject defaultDataSourceNodeObject = DataSourceNodeObject.getEmptyDataSourceNodeObject();
        schemaRoot.add(new DefaultMutableTreeNode(defaultDataSourceNodeObject));
        return new DefaultTreeModel(schemaRoot);
    }
}
